
package com.probiz.estore.core.util;

import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.util.ValidatorUtils;
import org.springframework.validation.Errors;
import org.springmodules.validation.commons.FieldChecks;

/**
 * ValidationUtil Helper class for performing custom validations that aren't
 * already included in the core Commons Validator.
 * <p>
 * <a href="ValidationUtil.java.html"> <i>View Source </i> </a>
 * </p>
 * 
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible </a>
 */
public class ValidationUtil {
	// ~ Methods
	// ================================================================

	private static final Log	logger	= LogFactory.getLog(FieldChecks.class);

	/**
	 * Extracts the value of the given bean. If the bean is <code>null</code>,
	 * the returned value is also <code>null</code>. If the bean is a
	 * <code>String</code> then the bean itself is returned. In all other
	 * cases, the <code>ValidatorUtils</code> class is used to extract the
	 * bean value using the <code>Field</code> object supplied.
	 * 
	 * @see ValidatorUtils#getValueAsString(Object, String)
	 */
	protected static String extractValue(Object bean, Field field) {
		String value = null;

		if (bean == null) {
			return null;
		} else if (bean instanceof String) {
			value = (String) bean;
		} else {
			value = ValidatorUtils.getValueAsString(bean, field.getProperty());
		}

		return value;
	}

	/**
	 * 验证是否数字串
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateNumber(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\d]*$";
		if (!GenericValidator.isBlankOrNull(value)
				&& !Pattern.matches(regex, value)) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}
	/**
	 * 验证是否正整数
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validatePositiveInteger(Object bean,
			ValidatorAction va, Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[1-9]+[\\d]*$";
		if (!GenericValidator.isBlankOrNull(value)){
			if(Pattern.matches(regex, value)) {
				try{
					Integer.parseInt(value);
					return true;
				}catch(Exception e){
					FieldChecks.rejectValue(errors, field, va);
					return false;
				}
			}else{
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}

		return true;
	}
	/**
	 * 验证是否为整数或小数(1-4位小数)。
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateDouble4(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\d]*(\\.\\d{1,4})?$";
		if (!GenericValidator.isBlankOrNull(value)){
			if(Pattern.matches(regex, value)) {
				try{
					Double.parseDouble(value);
					return true;
				}catch(Exception e){
					FieldChecks.rejectValue(errors, field, va);
					return false;
				}
			}else{
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}

		return true;
	}

	/**
	 * 验证最小值
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateMinValue(Object bean, ValidatorAction va,
			Field field, Errors errors) {

		String value = extractValue(bean, field);

		if (!GenericValidator.isBlankOrNull(value)) {
			try {
				double min = Double.parseDouble(field.getVarValue("minValue"));
				double val = Double.parseDouble(value);

				if (val < min) {
					FieldChecks.rejectValue(errors, field, va);

					return false;
				}else{
					return true;
				}
			} catch (Exception e) {
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}

		return true;
	}

	/**
	 * 验证最大值
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateMaxValue(Object bean, ValidatorAction va,
			Field field, Errors errors) {

		String value = extractValue(bean, field);

		if (!GenericValidator.isBlankOrNull(value)) {
			try {
				double max = Double.parseDouble(field.getVarValue("maxValue"));
				double val = Double.parseDouble(value);

				if (val > max) {
					FieldChecks.rejectValue(errors, field, va);
					return false;
				}else{
					return true;
				}
			} catch (Exception e) {
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}

		return true;
	}

	/**
	 * Checks if the field is a valid code string. A word character:
	 * [a-zA-Z_0-9]
	 * 
	 * @param bean
	 *            The bean validation is being performed on.
	 * @param va
	 *            The <code>ValidatorAction</code> that is currently being
	 *            performed.
	 * @param field
	 *            The <code>Field</code> object associated with the current
	 *            field being validated.
	 * @param errors
	 *            The <code>Errors</code> object to add errors to if any
	 *            validation errors occur. -param request Current request
	 *            object.
	 * @return A Date if valid, a null if blank or invalid.
	 */
	public static boolean validateCode(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\w-\\d]+$";
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	public static boolean validateChineseCode(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\w-\\d\u4E00-\u9FA5]+$";
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	/**
	 * 验证电话
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validatePhone(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^(([0\\+]\\d{2,3}-)?(0\\d{2,3})-)?(\\d{7,8})(-(\\d{3,}))?$";
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	/**
	 * 验证手机
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateMobile(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^(13[0-9]|15[0|3|6|7|8|9]|18[6|8|9])\\d{8}$";
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	/**
	 * 验证邮件地址
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateEmail(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^([\\w-]+)(.[\\w-]+)*@([\\w-]+\\.){1,5}([A-Za-z]){2,4}$";
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	/**
	 * 验证url
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateUrl(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		StringBuffer sb = new StringBuffer(200);
		sb.append("^((https|http|ftp|rtsp|mms)?://)?");
		sb.append("(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?"); // ftp的user@
		sb.append("(([0-9]{1,3}\\.){3}[0-9]{1,3}"); // IP形式的URL- 199.194.52.184
		sb.append("|"); // 允许IP和DOMAIN（域名）
		sb.append("([0-9a-zA-Z_!~*'()-]+\\.)*"); // 域名- www.
		sb.append("([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\\."); // 二级域名
		sb.append("[a-zA-Z]{2,6})"); // first level domain- .com or .museum
		sb.append("(:[0-9]{1,5})?"); // 端口- :80
		sb.append("((/?)|"); // a slash isn't required if there is no file name
		sb.append("(/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+/?)$");
		String regex = sb.toString();
		if (!GenericValidator.isBlankOrNull(value)
				&& (!Pattern.matches(regex, value))) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}

		return true;
	}

	/**
	 * Checks if the field is a valid date. If the field has a datePattern
	 * variable, that will be used to format
	 * <code>java.text.SimpleDateFormat</code>. If the field has a
	 * datePatternStrict variable, that will be used to format
	 * <code>java.text.SimpleDateFormat</code> and the length will be checked
	 * so '2/12/1999' will not pass validation with the format 'MM/dd/yyyy'
	 * because the month isn't two digits. If no datePattern variable is
	 * specified, then the field gets the DateFormat.SHORT format for the
	 * locale. The setLenient method is set to <code>false</code> for all
	 * variations.
	 * 
	 * @param bean
	 *            The bean validation is being performed on.
	 * @param va
	 *            The <code>ValidatorAction</code> that is currently being
	 *            performed.
	 * @param field
	 *            The <code>Field</code> object associated with the current
	 *            field being validated.
	 * @param errors
	 *            The <code>Errors</code> object to add errors to if any
	 *            validation errors occur. -param request Current request
	 *            object.
	 * @return A Date if valid, a null if blank or invalid.
	 */
	public static boolean validateDate(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		try {
			if(PropertyUtils.getProperty(bean, field.getKey()) instanceof Date){
				return true;
			}
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (InvocationTargetException e1) {
			e1.printStackTrace();
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		}
		
		String value = ValidationUtil.extractValue(bean, field);
		if (!GenericValidator.isBlankOrNull(value)){
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 
			try{
				df.parse(value);
				return true;
			}catch(Exception e)	{
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}
		return true;
	}

	/**
	 * 只是简单检查是否含有HTML标记
	 * 
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateNoHtml(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		if (!GenericValidator.isBlankOrNull(value)){
			if(value.indexOf("<") != -1 || value.indexOf(">") != -1) {
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}	
		}
		return true;

		// String regex = ".*<(\\w+)\\b[^>]*>.*?</\\1>.*|.*<(\\w+)\\b[^>]*/>.*";
		//
		// if (Pattern.matches(regex, value)) {
		// FieldChecks.rejectValue(errors, field, va);
		// return false;
		// }

	}

	/**
	 * 验证价格
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validatePrice(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\d]{1,10}(\\.\\d{1,2})?$";
		if (!GenericValidator.isBlankOrNull(value) && !Pattern.matches(regex, value)) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}
		return true;
	}
	/**
	 * 验证金额
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 * @return
	 */
	public static boolean validateMoney(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidationUtil.extractValue(bean, field);
		String regex = "^[\\d]{1,10}(\\.\\d{1,2})?$";
		if (!GenericValidator.isBlankOrNull(value) && !Pattern.matches(regex, value)) {
			FieldChecks.rejectValue(errors, field, va);
			return false;
		}
		return true;
	}

	/**
	 * 验证两个字段是否匹配
	 * @param bean
	 * @param va
	 * @param field
	 * @param errors
	 */
	public static boolean validateTwoFields(Object bean, ValidatorAction va,
			Field field, Errors errors) {
		String value = ValidatorUtils.getValueAsString(bean, field
				.getProperty());
		String sProperty2 = field.getVarValue("secondProperty");
		String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

		if (!GenericValidator.isBlankOrNull(value)) {
			try {
				if (!value.equals(value2)) {
					FieldChecks.rejectValue(errors, field, va);
					return false;
				}
			} catch (Exception e) {
				FieldChecks.rejectValue(errors, field, va);
				return false;
			}
		}

		return true;
	}
}
